#pragma once

#include <stdint.h>

#include "./yield.hpp"
#include "./arch.hpp"


#ifdef clockCyclesPerMicrosecond
    #undef clockCyclesPerMicrosecond
#endif

#ifdef clockCyclesToMicroseconds
    #undef clockCyclesToMicroseconds
#endif

#ifdef microsecondsToClockCycles
    #undef microsecondsToClockCycles
#endif


namespace arduino_basic {

    using TimeType = uint32_t;


    constexpr uint32_t clockCyclesPerMicrosecond() {
        return F_CPU / 1000000L;
    }


    constexpr uint32_t clockCyclesToMicroseconds(uint32_t t) {
        return t / clockCyclesPerMicrosecond();
    }


    constexpr uint32_t microsecondsToClockCycles(uint32_t t) {
        return t * clockCyclesPerMicrosecond();
    }


    TimeType millis() __attribute__((weak));

    TimeType micros() __attribute__((weak));

    void delayMicroseconds(TimeType t) __attribute__((weak));

    // TODO
    // using TimeSource


    


    // TODO
    class TimeCycle {
       private:
        TimeType _start;

       public:
        TimeCycle() {
            reset();
        }

        void reset() {
            _start = millis();
        }

        /**
         * @brief 周期性延时指定的时间
         *
         * 每次延时结束时返回true，同时自动更新参考时间，从而开启下一个延时周期。
         *
         * @param duration 时间
         * @return true    一个延时周期结束
         * @return false   当前延时周期未结束
         */
        bool cycle(TimeType duration) {
            if (this->expired(duration)) {
                reset();
                return true;
            }
            return false;
        }

        /**
         * @brief 非阻塞延时指定的时间
         *
         * 延时结束不自动更新参考时间，一次延时结束后，返回值保持为true。
         *
         * @param duration 时间
         * @return true    已经过了指定的时间
         * @return false   延时尚未结束
         */
        bool expired(TimeType duration) {
            return (millis() - _start) > duration;
        }

        /**
         * @brief 非阻塞延时指定的时间
         *
         * 与expired 相同，只是返回值逻辑相反，一次延时结束后，返回值保持为false
         *
         * @param duration
         * @return true
         * @return false
         */
        bool wait(TimeType duration) {
            return !expired(duration);
        }
    };


    void delay(TimeType ms) {
        TimeCycle tc;

        while (tc.wait(ms)) {
            yield();
        }
    }
}  // namespace arduino_basic